<html>
<head>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="canonical" href="./RAM_1WnR_Replicated.html">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Implements a memory with a single write port and multiple concurrent read ports (1WnR) by replicating the storage once for each read port and having writes go to all replicated storage banks. The implementation of the storage is set by a parameter.">
<title>RAM 1WnR Replicated</title>
</head>
<body>

<p class="inline bordered"><b><a href="./RAM_1WnR_Replicated.v">Source</a></b></p>
<p class="inline bordered"><b><a href="./legal.html">License</a></b></p>
<p class="inline bordered"><b><a href="./index.html">Index</a></b></p>

<h1>Multi-Ported Memory using Replication (1WnR)</h1>
<p>Implements a memory with a single write port and multiple concurrent read
 ports (1WnR) by replicating the storage once for each read port and having
 writes go to all replicated storage banks. The implementation of the
 storage is set by a parameter.</p>
<p>There is no synchronous clear on the output: In Quartus at least, any
 register driving it cannot be retimed, and it may not be as portable.
 Instead, use separate logic (e.g.: an <a href="./Annuller.html">Annuller</a>) to
 zero-out the output down the line.</p>
<h2>Write Forwarding</h2>
<p>The READ_NEW_DATA parameter control the behaviour of simultaneous reads and
 writes to the same address. This is the most important parameter when
 considering what kind of memory block the CAD tool will infer.</p>
<ul>
<li><code>READ_NEW_DATA = 0</code> describes a memory which returns the OLD value (in the
 memory) on coincident read and write (no write-forwarding).  This is
 well-suited for LUT-based memory, such as MLABs.</li>
<li><code>READ_NEW_DATA = 1</code> (or any non-zero value) describes a memory which
 returns NEW data (from the write) on coincident read and write, usually by
 inferring some surrounding write-forwarding logic.  Good for dedicated
 Block RAMs, such as M10K.</li>
</ul>
<p>The inferred write-forwarding logic also allows the RAM to operate at
 higher frequency, since a read corrupted by a simultaneous write to the
 same address will be discarded and replaced by the write value at the
 output mux of the forwarding logic. Otherwise, the RAM must internally
 perform the write on one edge of the clock, and the read on the other,
 which requires a longer cycle time.</p>
<h3>Quartus</h3>
<p>For Quartus, if you do not want write-forwarding, but still get the higher
 speed at the price of indeterminate behaviour on coincident read/writes,
 use "no_rw_check" as part of the RAMSTYLE (e.g.: "M10K, no_rw_check").
 Depending on the FPGA hardware, this may also help when returning OLD data.
 If that fails, add this setting to your Quartus project:
 <code>set_global_assignment -name ADD_PASS_THROUGH_LOGIC_TO_INFERRED_RAMS OFF</code>
 to disable creation of write-forwarding logic, as Quartus ignores the
 "no_rw_check" RAMSTYLE for M10K BRAMs.</p>
<h3>Vivado</h3>
<p>Vivado uses a different mechanism to control write-forwarding: set
 RW_ADDR_COLLISION to "yes" to force the inference of write forwarding
 logic, or "no" to prevent it. Otherwise, set it to "auto".</p>

<pre>
`default_nettype none

module <a href="./RAM_1WnR_Replicated.html">RAM_1WnR_Replicated</a>
#(
    parameter                       WORD_WIDTH          = 0,
    parameter                       READ_PORT_COUNT     = 0,
    parameter                       ADDR_WIDTH          = 0,
    parameter                       DEPTH               = 0,
    parameter                       USE_INIT_FILE       = 0,
    parameter                       INIT_FILE           = "",
    parameter   [WORD_WIDTH-1:0]    INIT_VALUE          = 0,
    parameter                       RAMSTYLE            = "",
    // See <a href="./RAM_Simple_Dual_Port.html">RAM_Simple_Dual_Port</a> for usage of these parameters
    parameter                       READ_NEW_DATA       = 0,
    parameter                       RW_ADDR_COLLISION   = "",

    // Do not set at instantiation, except in IPI
    parameter TOTAL_READ_DATA  = WORD_WIDTH * READ_PORT_COUNT,
    parameter TOTAL_READ_ADDR  = ADDR_WIDTH * READ_PORT_COUNT
)
(
    input   wire                            clock,

    input   wire    [WORD_WIDTH-1:0]        write_data,
    input   wire    [ADDR_WIDTH-1:0]        write_address,
    input   wire                            write_enable,

    output  wire    [TOTAL_READ_DATA-1:0]   read_data,
    input   wire    [TOTAL_READ_ADDR-1:0]   read_address,
    input   wire    [READ_PORT_COUNT-1:0]   read_enable
);
</pre>

<p>There is no logic: it's a number of copies of 1W1R memories with the write
 ports tied together. It's not the most area-efficient method, but it is the
 simplest, fastest, and most flexible when it fits.</p>

<pre>
    generate
    genvar i;

        for (i=0; i < READ_PORT_COUNT; i=i+1) begin: per_read_port

            <a href="./RAM_Simple_Dual_Port.html">RAM_Simple_Dual_Port</a>
            #(
                .WORD_WIDTH         (WORD_WIDTH),
                .ADDR_WIDTH         (ADDR_WIDTH),
                .DEPTH              (DEPTH),
                .RAMSTYLE           (RAMSTYLE),
                .READ_NEW_DATA      (READ_NEW_DATA),
                .RW_ADDR_COLLISION  (RW_ADDR_COLLISION),
                .USE_INIT_FILE      (USE_INIT_FILE),
                .INIT_FILE          (INIT_FILE),
                .INIT_VALUE         (INIT_VALUE)
            )
            Replicated_Storage_Bank
            (
                .clock              (clock),
                .wren               (write_enable),
                .write_addr         (write_address),
                .write_data         (write_data),
                .rden               (read_enable  [i]),
                .read_addr          (read_address [ADDR_WIDTH*i +: ADDR_WIDTH]),
                .read_data          (read_data    [WORD_WIDTH*i +: WORD_WIDTH])
            );

        end

    endgenerate

endmodule
</pre>

<hr>
<p><a href="./index.html">Back to FPGA Design Elements</a>
<center><a href="https://fpgacpu.ca/">fpgacpu.ca</a></center>
</body>
</html>

